package com.zhouwr.common.metadata;

import com.zhouwr.common.metadata.unit.UnifyUnit;
import lombok.Getter;
import lombok.Setter;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Optional;
import java.util.function.Function;

@Getter
@Setter
public abstract class NumberData<N extends Number> extends AbstractData<NumberData<N>> implements DataType, Converter<N> {

    //最大值
    private Number max;

    //最小值
    private Number min;

    //单位
    private UnifyUnit unit;

    public boolean isNumber(Object value) {
        return this.validate(value).isSuccess();
    }


    public Object format(Object value) {
        if (value == null) {
            return null;
        }
        if (unit == null) {
            return value;
        }
        return value;
    }

    @Override
    public ValidateResult validate(Object value) {
        try {
            N numberValue = convert(value);
            if (numberValue == null) {
                return ValidateResult.fail("数字格式错误:" + value);
            }
            if (max != null && numberValue.doubleValue() > max.doubleValue()) {
                return ValidateResult.fail("超过最大值:" + max);
            }
            if (min != null && numberValue.doubleValue() < min.doubleValue()) {
                return ValidateResult.fail("小于最小值:" + min);
            }
            return ValidateResult.success(numberValue);
        } catch (NumberFormatException e) {
            return ValidateResult.fail(e.getMessage());
        }
    }

    public N convertNumber(Object value, Function<Number, N> mapper) {
        return Optional.ofNullable(convertNumber(value))
                .map(mapper)
                .orElse(null);
    }

    public Number convertNumber(Object value) {
        if (value instanceof Number) {
            return ((Number) value);
        }
        if (value instanceof String) {
            try {
                return new BigDecimal(((String) value));
            } catch (NumberFormatException e) {
                return null;
            }
        }
        if (value instanceof Date) {
            return ((Date) value).getTime();
        }
        return null;
    }

    public abstract N convert(Object value);
}
